package xcmg.device.service.purchase;

import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import xcmg.device.dao.entity.PriMaterialsDO;
import xcmg.device.dao.entity.barcode.BarcodeManageDO;
import xcmg.device.dao.entity.company.CompanySupplierDO;
import xcmg.device.dao.entity.logistics.SendBillDetailDO;
import xcmg.device.dao.entity.purchase.PurchaseInboundDO;
import xcmg.device.dao.entity.purchase.PurchaseInboundDetailDO;
import xcmg.device.dao.entity.purchase.PurchaseRequestDO;
import xcmg.device.dao.entity.warehouse.WarehouseDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDO;
import xcmg.device.dao.mapper.BarcodeManageMapper;
import xcmg.device.dao.mapper.CompanySupplierMapper;
import xcmg.device.dao.mapper.PriMaterialsMapper;
import xcmg.device.dao.mapper.PurchaseInboundDetailMapper;
import xcmg.device.dao.mapper.PurchaseInboundMapper;
import xcmg.device.dao.mapper.PurchaseRequestMapper;
import xcmg.device.dao.mapper.logistics.SendBillDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseAreaLocationDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundMapper;
import xcmg.device.infra.DateUtil;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.infra.exception.CommonBusiExceptions;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.basic.CommonGenService;
import xcmg.device.service.vo.FunctionResult;
import xcmg.device.service.vo.basic.MaterialsSearchVO;
import xcmg.device.service.vo.basic.MaterialsVO;
import xcmg.device.service.vo.purchase.PurchaseInboundAddVO;
import xcmg.device.service.vo.purchase.PurchaseInboundDetailVO;
import xcmg.device.service.vo.purchase.PurchaseInboundVO;
import xcmg.device.service.warehouse.CommonService;
import xcmg.device.service.warehouse.WarehouseInboundService;
import xcmg.device.util.DecimalUtil;
import xcmg.device.util.ExcelUtil;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.PageHelperPlus;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PurchaseInboundService {

    @Autowired
    private CommonGenService commmonGenService;

    @Autowired
    private GenDocumentService genDocumentService;

    @Autowired
    private PurchaseInboundMapper purchaseInboundMapper;

    @Autowired
    private PurchaseInboundDetailMapper purchaseInboundDetailMapper;

    @Autowired
    private WarehouseDOMapper warehouseDOMapper;

    @Autowired
    private BarcodeManageMapper barcodeManageMapper;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private CommonService commonService;

    @Autowired
    private WarehouseInboundService warehouseInboundService;

    @Autowired
    private PurchaseRequestService purchaseRequestService;

    @Autowired
    private PriMaterialsMapper priMaterialsMapper;

    @Autowired
    private PurchaseRequestMapper purchaseRequestMapper;

    @Autowired
    private WarehouseInboundDetailMapper warehouseInboundDetailMapper;


    @Autowired
    private CompanySupplierMapper companySupplierMapper;

    @Autowired
    private WarehouseInboundMapper warehouseInboundMapper;

    @Autowired
    private WarehouseAreaLocationDOMapper warehouseAreaLocationDOMapper;

    @Autowired
    private SendBillDetailMapper sendbillDetailMapper;

    /**
     * @Author: WangKe
     * @Description: 选择多条采购申请单生成入库单
     * @Date: 2018/10/22 0022
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode batchAdd(PurchaseInboundAddVO purchaseInboundAddVO, String userId, String orgId) throws Exception {
        if (ListUtil.isNullOrEmpty(purchaseInboundAddVO.getDetailList())) {
            return ErrorCode.IllegalArument;
        }
        Map<String, List<PurchaseInboundDetailVO>> map = new HashMap<>(purchaseInboundAddVO.getDetailList().size());
        List<PurchaseInboundDetailVO> list;
        for (PurchaseInboundDetailVO inboundDetailVO : purchaseInboundAddVO.getDetailList()) {
            if (map.containsKey(inboundDetailVO.getPurchaseRequestOrder())) {
                map.get(inboundDetailVO.getPurchaseRequestOrder()).add(inboundDetailVO);
            } else {
                list = new ArrayList<>();
                list.add(inboundDetailVO);
                map.put(inboundDetailVO.getPurchaseRequestOrder(), list);
            }
        }
        ErrorCode errorCode = ErrorCode.Success;
        for (Map.Entry<String, List<PurchaseInboundDetailVO>> entry : map.entrySet()) {
            if (!StringUtils.isBlank(entry.getKey())) {
                purchaseInboundAddVO.getHeaderInfo().setPurchaseRequestOrder(entry.getKey());
            }
            purchaseInboundAddVO.setDetailList(entry.getValue());
            try {
                errorCode = this.add(purchaseInboundAddVO, userId, orgId);
            } catch (Exception e) {
                log.error("批量新增入库单失败", e);
                throw new Exception(e.getMessage());
            }
            if (errorCode.getCode() != 0) {
                throw new Exception(errorCode.getDesc());
            }
        }
        return errorCode;
    }

    /**
     * @Author: WangKe
     * @Description: 新增采购入库单
     * @Date: 2018/3/19 0019
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode add(PurchaseInboundAddVO purchaseInboundAddVO, String userId, String orgId) throws Exception {
        PurchaseInboundDO purchaseInboundDO = new PurchaseInboundDO();
        BeanUtils.copyProperties(purchaseInboundAddVO.getHeaderInfo(), purchaseInboundDO);
        boolean fromRequest = false;
        if (StringUtils.isNotBlank(purchaseInboundDO.getPurchaseRequestOrder())) {
            PurchaseRequestDO requestDO = purchaseRequestMapper.itemByPurchase(purchaseInboundDO.getPurchaseRequestOrder(), orgId);
            if (requestDO != null) {
                fromRequest=true;
                purchaseInboundDO.setPurchaseRequestOrder(requestDO.getBillNo());
                purchaseInboundDO.setSupplierName(requestDO.getSupplierOrgName());
                purchaseInboundDO.setSupplierOrgId(requestDO.getSupplierOrgId());
            }
            if (requestDO != null && requestDO.getSendStatus() > 0) {
                throw new CommonBusiExceptions("采购单已经创建送货单，无法创建采购入库单");
            }
        }
        purchaseInboundDO.setId(commmonGenService.textIdWithException());
        purchaseInboundDO.setPurchaseInboundOrder(genDocumentService.genDocumentNo(BillDesc.PurchaseInbound, orgId));
        purchaseInboundDO.setOrgId(orgId);
        purchaseInboundDO.setCreateId(userId);
        purchaseInboundDO.setCreateName(commonService.getUserName(userId));
        purchaseInboundDO.setCreateDate(new Date());
        purchaseInboundDO.setStatus(0);

        //先判断入库意向数量是否大于剩余数量
        boolean success;
        BigDecimal temp;
        for (PurchaseInboundDetailVO detailVO : purchaseInboundAddVO.getDetailList()) {
            if (null == detailVO.getSendQty()) {
                detailVO.setSendQty(BigDecimal.ZERO);
            }
            temp = detailVO.getSendQty().add(detailVO.getAmount());
            if (temp.compareTo(detailVO.getQty()) > 0) {
                throw new CommonBusiExceptions("入库数量不能大于剩余数量");
            }
            if (detailVO.getAmount() == null || detailVO.getAmount().compareTo(BigDecimal.ZERO) == 0) {
                throw new CommonBusiExceptions("入库数量必须大于0");
            }
        }
        for (PurchaseInboundDetailVO detailVO : purchaseInboundAddVO.getDetailList()) {
            PurchaseInboundDetailDO purchaseInboundDetailDO = new PurchaseInboundDetailDO();
            BeanUtils.copyProperties(detailVO, purchaseInboundDetailDO);

            purchaseInboundDetailDO.setId(commmonGenService.textIdWithException());
            purchaseInboundDetailDO.setPurchaseInboundOrder(purchaseInboundDO.getPurchaseInboundOrder());
            purchaseInboundDetailDO.setRealAmount(BigDecimal.ZERO);
            purchaseInboundDetailDO.setSendQty(detailVO.getSendQty().add(detailVO.getAmount()));
            purchaseInboundDetailDO.setStatus(0);
            purchaseInboundDetailDO.setCreateId(userId);
            purchaseInboundDetailDO.setCreateName(commonService.getUserName(userId));
            purchaseInboundDetailDO.setCreateDate(new Date());
            purchaseInboundDetailDO.setOrgId(orgId);
            if (purchaseInboundDetailDO.getPrice() != null) {
                purchaseInboundDetailDO.setTotalPrice(purchaseInboundDetailDO.getPrice()
                        .multiply(purchaseInboundDetailDO.getAmount()).setScale(2, BigDecimal.ROUND_HALF_UP));
            }
            //判断基础表里是否有此零件，如果没有就新增
            PriMaterialsDO priMaterialsDO = priMaterialsMapper.itemByNo(detailVO.getMaterialNo(), orgId);
            if (priMaterialsDO == null) {
                PriMaterialsDO newPriMaterialsDO = priMaterialsMapper.itemByNo(detailVO.getMaterialNo(), purchaseInboundDO.getSupplierOrgId());
                if (newPriMaterialsDO == null) {
                    throw new CommonBusiExceptions("供应商基础零件中未找到此零件，" + detailVO.getMaterialName());
                }
                priMaterialsDO = new PriMaterialsDO();
                BeanUtils.copyProperties(newPriMaterialsDO, priMaterialsDO);
                priMaterialsDO.setStockLocation(null);
                priMaterialsDO.setOrgId(orgId);
                priMaterialsDO.setStandardPrice(new BigDecimal("0"));
                priMaterialsDO.setAgentPurchasePrice(newPriMaterialsDO.getPrice());
                //获取代理商目录零售指导价
                String materialsNo = priMaterialsDO.getMaterialsNo();
                String supplierOrgId = newPriMaterialsDO.getOrgId();
                priMaterialsDO.setPrice(priMaterialsMapper.getGuidePrice(materialsNo, supplierOrgId));
                success = priMaterialsMapper.insert(priMaterialsDO) > 0;
                if (!success) {
                    throw new CommonBusiExceptions("向基础零件中新增此零件失败，" + detailVO.getMaterialName());
                }
            }
            purchaseInboundDetailDO.setMaterialType(priMaterialsDO.getMaterialsType());
            success = purchaseInboundDetailMapper.insert(purchaseInboundDetailDO) > 0;
            if (!success) {
                throw new CommonBusiExceptions("生成采购入库详情记录失败");
            }

            //更新其他采购入库单的已入库意向数量
            purchaseInboundDetailMapper.updateSendQty(orgId, purchaseInboundDetailDO.getSendQty(),
                    purchaseInboundDO.getPurchaseRequestOrder(), purchaseInboundDetailDO.getMaterialNo());

            if (fromRequest) {
                //更新采购申请详情入库意向数量
                success = purchaseRequestService.updateSendQty(purchaseInboundDO.getPurchaseRequestOrder(), purchaseInboundDetailDO.getMaterialNo(),
                        purchaseInboundDetailDO.getSendQty(), purchaseInboundDetailDO.getRowNo(), orgId);
                if (!success) {
                    throw new CommonBusiExceptions("更新采购申请详情入库意向数量失败");
                }
            }
        }
        success = purchaseInboundMapper.insert(purchaseInboundDO) > 0;
        if (!success) {
            throw new CommonBusiExceptions("生成采购入库主记录失败");
        }

        if (fromRequest) {
            //更新采购申请单的可否生成入库单状态
            success = purchaseRequestService.updateInboundEnable(purchaseInboundDO.getPurchaseRequestOrder(), orgId);
            if (!success) {
                throw new CommonBusiExceptions("更新采购申请单的可否生成入库单状态失败");
            }
        }
        //生成入库事物单
        purchaseInboundAddVO.getHeaderInfo().setPurchaseInboundOrder(purchaseInboundDO.getPurchaseInboundOrder());
        success = warehouseInboundService.saveByPurchaseInbound(purchaseInboundAddVO, userId, orgId);
        if (!success) {
            throw new CommonBusiExceptions("生成入库事物单失败");
        }
        return ErrorCode.Success;
    }

    /**
     * @Author: WangKe
     * @Description: 删除采购入库单
     * @Date: 2018/3/19 0019
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode remove(List<String> ids, String orgId) throws Exception {
        if (ListUtil.isNullOrEmpty(ids)) {
            return ErrorCode.IllegalArument;
        }
        if (!ListUtil.isNullOrEmpty(purchaseInboundMapper.findForDeleteByIds(ids))) {
            return ErrorCode.PurchaseInboundDeleteError;
        }
        List<String> orderList = purchaseInboundMapper.findOrderList(ids);
        List<PurchaseInboundDO> purchaseNoList = purchaseInboundMapper.findPurchaseNoList(ids);
        if (ListUtil.isNullOrEmpty(orderList) || ListUtil.isNullOrEmpty(purchaseNoList)) {
            return ErrorCode.IllegalArument;
        }
        Map<String, String> map = new HashMap<>();
        for (PurchaseInboundDO inboundDO : purchaseNoList) {
            map.put(inboundDO.getPurchaseInboundOrder(), inboundDO.getPurchaseRequestOrder());
        }
        List<PurchaseInboundDetailDO> detailDOList;
        boolean success;
        //更新采购申请单、其他采购入库单入库数量
        for (String order : orderList) {
            detailDOList = purchaseInboundDetailMapper.findByOrder(order, orgId);
            if (ListUtil.isNullOrEmpty(detailDOList)) {
                throw new Exception("删除失败");
            }
            for (PurchaseInboundDetailDO detailDO : detailDOList) {
                success = purchaseRequestService.updateSendQty(map.get(detailDO.getPurchaseInboundOrder()), detailDO.getMaterialNo(),
                        detailDO.getSendQty().subtract(detailDO.getAmount()), detailDO.getRowNo(), orgId);
                if (!success) {
                    if (ListUtil.isNullOrEmpty(detailDOList)) {
                        throw new Exception("更新采购申请单入库意向数量失败");
                    }
                }
                //更新其他采购入库单的已入库意向数量
                purchaseInboundDetailMapper.updateSendQty(orgId, detailDO.getSendQty().subtract(detailDO.getAmount()),
                        map.get(detailDO.getPurchaseInboundOrder()), detailDO.getMaterialNo());

            }
            //更新采购申请单的可否生成入库单状态
            success = purchaseRequestService.updateInboundEnable(map.get(order), orgId);
//            if (!success) {
//                throw new Exception("更新采购申请单的可否生成入库单状态失败");
//            }
        }
        success = purchaseInboundMapper.remove(ids) > 0;
        if (!success) {
            throw new Exception("删除主表记录失败");
        }
        success = purchaseInboundDetailMapper.removeByOrderList(orderList, orgId) > 0;
        if (!success) {
            throw new Exception("删除详情记录失败");
        }
        //删除入库事物单
        success = warehouseInboundService.removeByBusinessOrders(orderList, orgId).getCode() == 0;
        if (!success) {
            throw new Exception("删除入库事物单失败");
        }
        return ErrorCode.Success;
    }

    /**
     * @Author: WangKe
     * @Description: 更新采购入库单
     * @Date: 2018/3/19 0019
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized ErrorCode update(PurchaseInboundAddVO purchaseInboundAddVO, String orgId) throws Exception {
        PurchaseInboundDO purchaseInboundDO = new PurchaseInboundDO();
        BeanUtils.copyProperties(purchaseInboundAddVO.getHeaderInfo(), purchaseInboundDO);

        //先判断入库数量是否大于剩余数量
        for (PurchaseInboundDetailVO detailVO : purchaseInboundAddVO.getDetailList()) {
            if (detailVO.getAmount().compareTo(detailVO.getRealAmount()) < 0) {
                return ErrorCode.PurchaseInboundAmountError;
            }
            BigDecimal temp = detailVO.getSendQty().subtract(detailVO.getLastAmount()).add(detailVO.getAmount());
            if (temp.compareTo(detailVO.getQty()) > 0) {
                return ErrorCode.PurchaseInboundQtyError;
            }
            if (detailVO.getAmount() == null || detailVO.getAmount().compareTo(BigDecimal.ZERO) == 0) {
                throw new Exception("入库数量必须大于0");
            }
        }
        boolean success;
        boolean allComplete = true;
        boolean someComplete = false;
        boolean manulComplete = false;
        for (PurchaseInboundDetailVO detailVO : purchaseInboundAddVO.getDetailList()) {
            PurchaseInboundDetailDO inboundDetailDO = purchaseInboundDetailMapper.selectByPrimaryKey(detailVO.getId());
            if (inboundDetailDO.getStatus() == 3) {
                manulComplete = true;
            }
            if (inboundDetailDO.getStatus() == 2 || inboundDetailDO.getStatus() == 3) {
                someComplete = true;
                continue;//已入库完成的零件或者结单的零件不可以编辑
            }

            PurchaseInboundDetailDO detailDO = new PurchaseInboundDetailDO();
            BeanUtils.copyProperties(detailVO, detailDO);
            detailDO.setSendQty(detailVO.getSendQty().subtract(detailVO.getLastAmount()).add(detailVO.getAmount()));

            if (detailDO.getAmount().compareTo(detailDO.getRealAmount()) > 0) {
                if (allComplete) {
                    allComplete = false;
                }
                if (detailDO.getRealAmount().compareTo(BigDecimal.ZERO) == 0) {
                    detailDO.setStatus(0);
                } else {
                    detailDO.setStatus(1);
                    someComplete = true;
                }
            } else {
                someComplete = true;
                detailDO.setStatus(2);
            }

            success = purchaseInboundDetailMapper.updateByPrimaryKey(detailDO) > 0;
            if (!success) {
                throw new Exception("更新采购入库详情记录失败");
            }

            //更新入库事物单详情记录
            ErrorCode errorCode = warehouseInboundService.updateDetailState(purchaseInboundDO.getPurchaseInboundOrder(), detailDO.getMaterialNo(),
                    detailDO.getAmount(), detailDO.getStatus(), orgId);
            if (errorCode.getCode() != 0) {
                throw new Exception("更新入库事物单详情记录失败");
            }

            //更新其他采购入库单的已入库意向数量
            purchaseInboundDetailMapper.updateSendQty(orgId, detailDO.getSendQty(), purchaseInboundDO.getPurchaseRequestOrder(), detailDO.getMaterialNo());

            //更新采购申请详情入库意向数量
            success = purchaseRequestService.updateSendQty(purchaseInboundDO.getPurchaseRequestOrder(), detailVO.getMaterialNo(),
                    detailDO.getSendQty(), detailDO.getRowNo(), orgId);
            if (!success) {
                log.error("更新采购申请详情入库意向数量失败{}",purchaseInboundDO);
//                throw new Exception("更新采购申请详情入库意向数量失败");
            }
        }
        if (allComplete) {
            if (manulComplete) {
                purchaseInboundDO.setStatus(3);
            } else {
                purchaseInboundDO.setStatus(2);
            }
        } else if (someComplete) {
            purchaseInboundDO.setStatus(1);
        } else {
            purchaseInboundDO.setStatus(0);
        }
        success = purchaseInboundMapper.updateByPrimaryKey(purchaseInboundDO) > 0;
        if (!success) {
            throw new Exception("更新采购入库记录失败");
        }

        //更新采购申请单的可否生成入库单状态
        success = purchaseRequestService.updateInboundEnable(purchaseInboundDO.getPurchaseRequestOrder(), orgId);
        if (!success) {
            log.error("更新采购申请单的可否生成入库单状态失败{}",purchaseInboundDO);
//            throw new Exception("更新采购申请单的可否生成入库单状态失败");
        }

        //更新出库事务单
        WarehouseInboundDO inboundDO = warehouseInboundMapper.selectByOrder(purchaseInboundDO.getPurchaseInboundOrder(), orgId);
        if (inboundDO == null) {
            throw new Exception("更新入库事务单记录失败");
        }
        inboundDO.setStatus(purchaseInboundDO.getStatus());
        inboundDO.setWarehouseCode(purchaseInboundDO.getWarehouseCode());
        inboundDO.setInArea(purchaseInboundDO.getInArea());
        inboundDO.setSapInArea(purchaseInboundDO.getSapInArea());
        success = warehouseInboundMapper.updateByPrimaryKeySelective(inboundDO) > 0;
        if (!success) {
            throw new Exception("更新入库事务单记录失败");
        }
        return ErrorCode.Success;
    }

    public ErrorCode receiptConfirm(String id, String userName) {
        PurchaseInboundDO inboundDO = new PurchaseInboundDO();
        inboundDO.setId(id);
        inboundDO.setIsReceipt(1);
        inboundDO.setReceiptUser(userName);
        inboundDO.setReceiptDate(new Date());
        return purchaseInboundMapper.updateByPrimaryKey(inboundDO) > 0 ? ErrorCode.Success : ErrorCode.Failure;
    }

    /**
     * @Author: WangKe
     * @Description: 查询采购入库单列表
     * @Date: 2018/3/19 0019
     */
    public PageCommonVO<PurchaseInboundVO> list(SearchCommonVO<PurchaseInboundVO> condition) {
        PageCommonVO<PurchaseInboundVO> result = new PageCommonVO();
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<PurchaseInboundDO> doList = purchaseInboundMapper.list(condition.getFilters());
        List<PurchaseInboundVO> voList = new ArrayList<>();
        for (PurchaseInboundDO entity : doList) {
            PurchaseInboundVO model = new PurchaseInboundVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        result.setPageInfo(new PageInfo(doList));
        result.setPageInfoList(voList);
        return result;
    }

    /**
     * @Author: WangKe
     * @Description: 根据id获取单条采购入库单记录
     * @Date: 2018/3/19 0019
     */
    public PurchaseInboundAddVO item(String id, String orgId) {
        PurchaseInboundAddVO result = new PurchaseInboundAddVO();
        PurchaseInboundDO purchaseInboundDO = purchaseInboundMapper.selectByPrimaryKey(id);
        if (purchaseInboundDO == null) {
            return result;
        }
        PurchaseRequestDO purchaseRequestDO = purchaseRequestMapper.itemByPurchase(purchaseInboundDO.getPurchaseRequestOrder(), orgId);
        PurchaseInboundVO purchaseInboundVO = new PurchaseInboundVO();
        BeanUtils.copyProperties(purchaseInboundDO, purchaseInboundVO);
        if (purchaseRequestDO != null) {
            purchaseInboundVO.setPurchaseVoucher(purchaseRequestDO.getVoucherNo());
            purchaseInboundVO.setPurchaseGroup(purchaseRequestDO.getPurchaseGroup());
        }
        CompanySupplierDO companySupplierDO = companySupplierMapper.itemBySupplierOrgId(purchaseInboundDO.getOrgId(), purchaseInboundDO.getSupplierOrgId());
        if (companySupplierDO != null) {
            purchaseInboundVO.setSupplierCode(companySupplierDO.getSupplierCode());
        }
        if (purchaseInboundVO.getPostTime() != null) {
            purchaseInboundVO.setPostTimeStr(DateUtil.formatDateTime(purchaseInboundVO.getPostTime()));
        }
        if (StringUtils.isNotBlank(purchaseInboundVO.getWarehouseCode())) {
            WarehouseDO warehouse = warehouseDOMapper.itemByWarehouseCode(orgId, purchaseInboundVO.getWarehouseCode());
            if (null != warehouse) {
                purchaseInboundVO.setWarehouseCodeDesc(warehouse.getDescription());
            }
        }
        List<BarcodeManageDO> barCodeList = barcodeManageMapper.selectByBusinessOrderMatOrgId(purchaseInboundDO.getPurchaseInboundOrder(), null, orgId);

        result.setHeaderInfo(purchaseInboundVO);
        List<PurchaseInboundDetailVO> listVO = new ArrayList<>();
        List<PurchaseInboundDetailDO> listDO = purchaseInboundDetailMapper.findByOrderForLocationUser(purchaseInboundDO.getPurchaseInboundOrder(), orgId);
        for (PurchaseInboundDetailDO entity : listDO) {
            PurchaseInboundDetailVO model = new PurchaseInboundDetailVO();
            BeanUtils.copyProperties(entity, model);
            String loactionCode = model.getStockLocation();
            if (StringUtils.isNotBlank(loactionCode)) {
                model.setLocationDesc(warehouseAreaLocationDOMapper.getLocationDesc(loactionCode));
            }
            // 如果是条码库则设置条码相关信息
            if(!ObjectUtils.isEmpty(barCodeList)) {
                // 设置条码字段（如果有拆分条码的情况，多个条码用逗号隔开，在入库时会拆开逐个入库）
                String barCodes = barCodeList.stream().filter(e -> Objects.equals(e.getMaterialsNo(), entity.getMaterialNo())).map(BarcodeManageDO::getBarcode).collect(Collectors.joining(","));
                model.setBarCode(barCodes);
            }
            listVO.add(model);
        }
        result.setDetailList(listVO);
        return result;
    }

    /**
     * @Author: WangKe
     * @Description: 导出部分采购申请列表
     * @Date: 2018/3/19 0019
     */
    public void export(List<String> ids) throws Exception {
        PurchaseInboundVO inboundVO = new PurchaseInboundVO();
        inboundVO.setSort("create_date desc");
        inboundVO.setIdsList(ids);
        invokeExport(purchaseInboundMapper.list(inboundVO));
    }

    /**
     * @Author: WangKe
     * @Description: 导出全部采购申请列表
     * @Date: 2018/3/19 0019
     */
    public void exportAll(PurchaseInboundVO condition) throws Exception {
        Integer count = purchaseInboundMapper.findCountForExportAll(condition);
        List<PurchaseInboundDO> dataList = new ArrayList<>();
        int times = count / 500 + 1;
        for (int i = 0; i < times; i++) {
            PageHelperPlus.startPage(i + 1, 500, "create_date desc");
            dataList.addAll(purchaseInboundMapper.list(condition));
        }
        invokeExport(dataList);
    }

    /**
     * @Author: WangKe
     * @Description: 导出采购申请列表
     * @Date: 2018/3/19 0019
     */
    private void invokeExport(List<PurchaseInboundDO> doList) throws Exception {
        String title = "采购入库数据导出";
        String[] rowsName = new String[]{"序号", "采购入库单号", "采购订单号", "供应商", "调入库位", "调入库区",
                "入库状态", "备注", "制单部门", "制单人部门", "制单时间", "零件编码", "零件名称", "零件类型", "单位", "单价",
                "总价", "订单总数", "已发总数", "本次入库数量", "实际入库数量", "零件状态", "行项目号", "储位", "保管员", "过账失败说明"};
        List<Object[]> dataList = new ArrayList<Object[]>();
        Object[] objs;
        for (int i = 0; i < doList.size(); i++) {

            PurchaseInboundDO exportDO = doList.get(i);
            List<PurchaseInboundDetailDO> details = purchaseInboundDetailMapper
                    .findByOrderForLocationUser(exportDO.getPurchaseInboundOrder(), exportDO.getOrgId());

            for (PurchaseInboundDetailDO detail : details) {
                objs = new Object[rowsName.length];
                objs[0] = i + 1;
                objs[1] = exportDO.getPurchaseInboundOrder();
                objs[2] = exportDO.getPurchaseRequestOrder();
                objs[3] = exportDO.getSupplierName();
                objs[4] = exportDO.getWarehouseCode();
                objs[5] = exportDO.getInArea();
                objs[6] = getState(exportDO.getStatus());
                objs[7] = exportDO.getNote();
                objs[8] = exportDO.getCreateName();
                objs[9] = exportDO.getDeptName();
                objs[10] = DateUtil.formatDateTime(exportDO.getCreateDate());

                objs[11] = detail.getMaterialNo();
                objs[12] = detail.getMaterialName();
                objs[13] = detail.getMaterialType();
                objs[14] = detail.getUnit();
                objs[15] = detail.getPrice();
                objs[16] = detail.getTotalPrice();
                objs[17] = detail.getQty();
                objs[18] = detail.getSendQty();
                objs[19] = detail.getAmount();
                objs[20] = detail.getRealAmount();
                objs[21] = getStatusDesc(detail.getStatus());
                objs[22] = detail.getRowNo();
                objs[23] = detail.getStockLocation();
                objs[24] = detail.getStockUserName();
                objs[25] = exportDO.getSapErrorMsg();
                dataList.add(objs);
            }
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    public String getStatusDesc(Integer status) {
        if (status.equals(1)) {
            return "部分完成";
        } else if (status.equals(2)) {
            return "完成";
        } else {
            return "未完成";
        }
    }


    public String getState(Integer state) {
        if (state == 0) {
            return "未入库";
        } else if (state == 1) {
            return "部分入库";
        } else if (state == 2) {
            return "已入库";
        } else if (state == 3) {
            return "强制结单";
        }
        return "未完成";
    }

    public PurchaseInboundDO getByPurchaseOrder(String purchaseOrder, String orgId) {
        return purchaseInboundMapper.findByInboundOrder(purchaseOrder, orgId);
    }

    /**
     * @Author: WangKe
     * @Description: 扫码入库时更新采购入库单主表和详情表相关记录状态
     * @Date: 2018/3/20 0020
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean updateByInbound(String purchaseOrder, String materialNo, BigDecimal realAmount,
                                   Integer singelState, Integer totalState, Integer rowNo, String orgId) throws Exception {
        PurchaseInboundDO inboundDO = purchaseInboundMapper.findByInboundOrder(purchaseOrder, orgId);
        if (inboundDO == null) {
            return false;
        }
        PurchaseInboundDetailDO detailDO = purchaseInboundDetailMapper.findByOrderAndMaterialNo(purchaseOrder, materialNo, orgId, rowNo);
        if (detailDO == null) {
            return false;
        }
        BigDecimal nowAmount = realAmount;
        if (detailDO.getRealAmount() != null) {
            nowAmount = realAmount.subtract(detailDO.getRealAmount());
        }
        detailDO.setRealAmount(realAmount);
        detailDO.setStatus(singelState);
        if (singelState != null && singelState.compareTo(2) == 0) {
            detailDO.setInboundFinishTime(new Date());
        }
        boolean success = purchaseInboundDetailMapper.updateByPrimaryKey(detailDO) > 0;
        if (success) {
            //更新采购入库单记录
            inboundDO.setStatus(totalState);
            if (totalState != null && totalState.compareTo(2) == 0) {
                inboundDO.setInboundFinishTime(new Date());
            }
            success = purchaseInboundMapper.updateByPrimaryKey(inboundDO) > 0;
            if (!success) {
                return false;
            }
            //更新采购申请单状态
            purchaseRequestService.updateByInBound(inboundDO.getPurchaseRequestOrder(), materialNo, nowAmount, rowNo, orgId);
        }
        return success;
    }

    public boolean backPurchaseAmount(String sendOrder, String materialNo, BigDecimal realAmount, Integer rowNo, String orgId) throws Exception {
        SendBillDetailDO sendBillDetailDO = sendbillDetailMapper.findMySendOrderAdndMaterialNo(sendOrder, materialNo, rowNo);
        if (sendBillDetailDO != null) {
            purchaseRequestService.updateBySendBillInBound(sendBillDetailDO.getSourceOrder(), materialNo, realAmount, null, orgId);
            if (sendBillDetailDO.getInitialOrder() != null) {
                purchaseRequestService.updateBySendBillInBound(sendBillDetailDO.getInitialOrder(), materialNo, realAmount, null, orgId);
            }
        }
        return true;
    }

    /**
     * 发货单直投更新入库
     *
     * @param purchaseOrder
     * @param materialNo
     * @param realAmount
     * @param singelState
     * @param totalState
     * @param rowNo
     * @param orgId
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean directUpdateByInbound(String purchaseOrder, String materialNo, BigDecimal realAmount,
                                         Integer singelState, Integer totalState, Integer rowNo, String orgId) throws Exception {
        PurchaseInboundDO inboundDO = purchaseInboundMapper.findByInboundOrder(purchaseOrder, orgId);
        if (inboundDO == null) {
            return false;
        }
        PurchaseInboundDetailDO detailDO = purchaseInboundDetailMapper.findByOrderAndMaterialNo(purchaseOrder, materialNo, orgId, rowNo);
        if (detailDO == null) {
            return false;
        }
        BigDecimal nowAmount = realAmount;
        if (detailDO.getRealAmount() != null) {
            nowAmount = realAmount.subtract(detailDO.getRealAmount());
        }
        detailDO.setRealAmount(realAmount);
        detailDO.setStatus(singelState);
        if (singelState != null && singelState.compareTo(2) == 0) {
            detailDO.setInboundFinishTime(new Date());
        }
        boolean success = purchaseInboundDetailMapper.updateByPrimaryKey(detailDO) > 0;
        if (success) {
            //更新采购入库单记录
            inboundDO.setStatus(totalState);
            if (totalState != null && totalState.compareTo(2) == 0) {
                inboundDO.setInboundFinishTime(new Date());
            }
            success = purchaseInboundMapper.updateByPrimaryKey(inboundDO) > 0;
            if (!success) {
                return false;
            }


            PurchaseRequestDO purchaseRequestDO = purchaseRequestMapper.itemByPurchase(inboundDO.getPurchaseRequestOrder(), orgId);

            //更新采购申请单状态
            success = purchaseRequestService.directUpdateByInBound(purchaseRequestDO, materialNo, nowAmount, rowNo, orgId);

            if (success) {
                //原采购入库单
                PurchaseRequestDO directSourceRequestDO = purchaseRequestMapper.itemByPurchase(purchaseRequestDO.getDirectSourceOrder(), purchaseRequestDO.getDeliveryOrgId());

                success = purchaseRequestService.directUpdateByInBound(directSourceRequestDO, materialNo, nowAmount, rowNo, purchaseRequestDO.getDeliveryOrgId());
            }
        }
        return success;
    }

    /**
     * 手动完成单据<br>
     * materialsNo 不为null,则更改该单据下的零件状态为“手动完成”状态；如果materialsNo为空，则更改整个单据为“手动完成”状态
     *
     * @param billNo      String 单据编号
     * @param materialsNo String 零件编号
     * @param orgId       String 企业ID
     * @return Er11rorCode 返回码
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode manualFinish(String billNo, String materialsNo, String orgId) throws Exception {
        PurchaseInboundDO purchaseInboundDO = purchaseInboundMapper.findByInboundOrder(billNo, orgId);
        if (purchaseInboundDO == null) {
            return ErrorCode.IllegalArument;
        }
        purchaseRequestService.updateByManulFinish(purchaseInboundDO, materialsNo, orgId);
//        if (!success) {
//            throw new Exception("更新采购申请状态失败");
//        }
        //todo  采购申请变更
        if (StringUtil.isNullOrEmpty(materialsNo))//零件编码为空，更新单据状态为“手动完成”
        {
            purchaseInboundMapper.updateStatus(3, billNo);
            warehouseInboundService.updateState(billNo, 3, orgId);

            purchaseInboundDetailMapper.updateStatus(3, billNo, null);
            warehouseInboundDetailMapper.updateAllStatus(3, billNo, orgId);
        } else {
            purchaseInboundDetailMapper.updateStatus(3, billNo, materialsNo);
            warehouseInboundService.updateDetailState(billNo, materialsNo, null, 3, orgId);
            ErrorCode errorCode = checkBillFinished(billNo, orgId);

            if (ErrorCode.Success != errorCode) {
                return errorCode;
            }
        }
        return ErrorCode.Success;
    }

    /**
     * 校验单据是否已完成<br>
     * 判断单据下的所有零件是否已经完成，如果都完成，则更改单据状态为完成
     *
     * @param billNo String
     * @param orgId  String
     * @return Boolean
     */
    private ErrorCode checkBillFinished(String billNo, String orgId) throws Exception {
        List<PurchaseInboundDetailDO> inboundDetailDOs = purchaseInboundDetailMapper.findByOrder(billNo, orgId);
        if (ListUtil.isNullOrEmpty(inboundDetailDOs)) {
            throw new Exception("未查询到采购入库单详情列表");
        }
        boolean manul = false;
        boolean flag = true;
        int status;
        for (PurchaseInboundDetailDO temp : inboundDetailDOs) {
            if (3 == temp.getStatus()) {
                manul = true;
            }
            if (2 == temp.getStatus() || 3 == temp.getStatus()) {
                //完成状态
                continue;
            }
            flag = false;
        }
        if (flag) {
            if (manul) {
                status = 3;
            } else {
                status = 2;
            }
        } else {
            status = 1;
        }
        purchaseInboundMapper.updateStatus(status, billNo);
        warehouseInboundService.updateState(billNo, status, orgId);
        return ErrorCode.Success;
    }


    public PurchaseInboundDetailDO getPurchaseInboundDetailDO(String purchaseOrder, String materialNo, Integer rowNo, String orgId) throws Exception {
        PurchaseInboundDO inboundDO = purchaseInboundMapper.findByInboundOrder(purchaseOrder, orgId);
        if (inboundDO == null) {
            return null;
        }
        PurchaseInboundDetailDO detailDO = purchaseInboundDetailMapper.findByOrderAndMaterialNo(purchaseOrder, materialNo, orgId, rowNo);
        if (detailDO == null) {
            return null;
        }
        return detailDO;
    }

    public PurchaseInboundDO getPurchaseOrderBySendOrder(String sendOrder, String orgId) {
        return purchaseInboundMapper.findPurchaseOrderBySendOrder(sendOrder, orgId);
    }

    public List<PurchaseInboundDetailDO> findByOrdersAndMaterialNo(String purchaseOrder, String materialNo, Integer rowNo, String orgId) {
        return purchaseInboundDetailMapper.findByOrdersAndMaterialNo(purchaseOrder, materialNo, orgId, rowNo);
    }

    public FunctionResult<List<PurchaseInboundDetailVO>> importExcel(InputStream in, String supplierOrgId, String orgId) throws IOException {
        FunctionResult<List<PurchaseInboundDetailVO>> result=new FunctionResult();
        HSSFWorkbook wb=new HSSFWorkbook(in);
        HSSFSheet sheet=wb.getSheetAt(0);
        int totalRow=sheet.getLastRowNum();
        if(totalRow<2){
            throw new CommonBusiExceptions("导入模板不正确");
        }
        int totalCell=sheet.getRow(1).getLastCellNum();
        if(totalCell!=5){
            throw new CommonBusiExceptions("导入模板不正确,列不正确");
        }
        List<PurchaseInboundDetailVO> detailVOList=new ArrayList<>(totalRow);
        List<PurchaseInboundDetailVO> successVOList=new ArrayList<>(totalRow);
//        List<PurchaseInboundDetailVO> errorDetailVOList=new ArrayList<>(totalRow);
        Set<String> materials=new HashSet<>(totalRow);
        for (int i=2;i<=totalRow;i++) {
            HSSFRow curRow = sheet.getRow(i);
            PurchaseInboundDetailVO detailVO = new PurchaseInboundDetailVO();
            if (curRow == null) {
                continue;
            }
            detailVO.setRownum(i + 1);
            String materialNo = ExcelUtil.getCellValue(curRow, 1);
            if (StringUtil.isNullOrEmpty(materialNo)) {
                detailVO.setRemark("零件编码不能为空");
                throw new CommonBusiExceptions(detailVO.getRowNo()+"行:零件编码不能为空");
//                errorDetailVOList.add(detailVO);
//                continue;
            }
            if(materials.contains(materialNo)){
                detailVO.setRemark("零件编码重复出现");
                throw new CommonBusiExceptions(detailVO.getRowNo()+"行:零件编码不能为空");
//                errorDetailVOList.add(detailVO);
//                continue;
            }
            detailVO.setMaterialNo(materialNo);
            materials.add(materialNo);
            String qtyStr = ExcelUtil.getCellValue(curRow, 3);
            detailVO.setQty(DecimalUtil.getStringDecimal(qtyStr));
            String amountStr = ExcelUtil.getCellValue(curRow, 4);
            detailVO.setAmount(DecimalUtil.getStringDecimal(amountStr));
            detailVOList.add(detailVO);
        }

        MaterialsSearchVO mv=new MaterialsSearchVO();
        mv.setSupplierOrgId(supplierOrgId);
        mv.setOrgId(orgId);
        mv.setMaterialsList(new ArrayList<>(materials));
        List<MaterialsVO> resultList  = priMaterialsMapper.querySupplierMaterials(mv);
        Map<String,MaterialsVO> map=resultList.stream().collect(Collectors.toMap(MaterialsVO::getMaterialsNo, v -> v));

        for(PurchaseInboundDetailVO v:detailVOList){
            MaterialsVO m = map.get(v.getMaterialNo());
            if (null==m){
                v.setRemark("零件编码在供货商下不存在");
                throw new CommonBusiExceptions(v.getRownum()+"行:零件编码在供货商下不存在");
//                errorDetailVOList.add(v);
//                continue;
            }
            v.setMaterialName(m.getMaterialsDes());
            v.setMaterialsDesEn(m.getMaterialsDesEn());
            v.setUnit(m.getUnit());
            v.setMaterialsShortNo(m.getMaterialsShortNo());
            successVOList.add(v);
        }
        result.setValue(successVOList);
        result.setCode(ErrorCode.Success);
        return result;
    }

}
